package cn.iocoder.yudao.module.jikong.service.user;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.OAuth2TokenCommonApi;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenCreateReqDTO;
import cn.iocoder.yudao.framework.common.biz.system.oauth2.dto.OAuth2AccessTokenRespDTO;
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
import cn.iocoder.yudao.framework.common.exception.ServiceException;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.erp.controller.app.auth.vo.*;
import cn.iocoder.yudao.module.erp.dal.dataobject.purchase.ErpSupplierDO;
import cn.iocoder.yudao.module.erp.service.AppCaptchaService;
import cn.iocoder.yudao.module.system.api.logger.LoginLogApi;
import cn.iocoder.yudao.module.system.api.logger.dto.LoginLogCreateReqDTO;
import cn.iocoder.yudao.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
import cn.iocoder.yudao.module.system.enums.logger.LoginLogTypeEnum;
import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
import cn.iocoder.yudao.module.system.enums.oauth2.OAuth2ClientConstants;
import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import cn.iocoder.yudao.module.jikong.controller.admin.user.vo.*;
import cn.iocoder.yudao.module.jikong.dal.dataobject.user.JkUserDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;

import cn.iocoder.yudao.module.jikong.dal.mysql.user.JkUserMapper;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.SUPPLIER_PHONE_EXIST;
import static cn.iocoder.yudao.module.erp.enums.ErrorCodeConstants.SUPPLIER_PHONE_NOT_EXIST;
import static cn.iocoder.yudao.module.jikong.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.jikong.enums.ErrorCodeConstants.USER_NOT_EXISTS;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.AUTH_LOGIN_BAD_CREDENTIALS;

/**
 * 用户 Service 实现类
 *
 * @author xc
 */
@Service
@Slf4j
@Validated
public class JkUserServiceImpl implements JkUserService {

    @Resource
    private JkUserMapper jkUserMapper;
    @Resource
    private PasswordEncoder passwordEncoder;
    @Autowired
    private AppCaptchaService appCaptchaService;
    @Resource
    private OAuth2TokenCommonApi oauth2TokenApi;
    @Resource
    private LoginLogApi loginLogApi;



    @Override
    public AppAuthLoginRespVO createUser(UserSaveReqVO createReqVO) {
        // 校验账号是否存在
        List<JkUserDO> users = jkUserMapper.selectList(new LambdaQueryWrapperX<JkUserDO>()
                .eq(JkUserDO::getMobile, createReqVO.getMobile()));

        //注册的时候，需要手机号不存在，存在代表该手机号已经注册过了
        if (!users.isEmpty()) {
            throw new ServiceException("该手机号已注册");
        }
        // 插入
        JkUserDO user = BeanUtils.toBean(createReqVO, JkUserDO.class);
        jkUserMapper.insert(user);
        // 返回token
        OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
                .setUserId(user.getId()).setUserType(getUserType().getValue())
                .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));

        return BeanUtils.toBean(accessTokenRespDTO, AppAuthLoginRespVO.class);
    }

    @Override
    public void updateUser(UserSaveReqVO updateReqVO) {

        log.info("===============" + JSONUtil.toJsonStr(updateReqVO));

        // 校验存在
        validateUserExists(updateReqVO.getId());
        // 更新
        JkUserDO updateObj = BeanUtils.toBean(updateReqVO, JkUserDO.class);

        log.info("===============" + JSONUtil.toJsonStr(updateObj));

        //如果状态改为已通过，则加上通过时间
        if (updateReqVO.getReviewStatus()!= null && updateReqVO.getReviewStatus() == 2) {
            updateObj.setPassTime(LocalDateTime.now());
        }
        log.info("===============" + JSONUtil.toJsonStr(updateObj));
        jkUserMapper.updateById(updateObj);
    }

    @Override
    public void deleteUser(Long id) {
        // 校验存在
        validateUserExists(id);
        // 删除
        jkUserMapper.deleteById(id);
    }

    @Override
        public void deleteUserListByIds(List<Long> ids) {
        // 校验存在
        validateUserExists(ids);
        // 删除
        jkUserMapper.deleteByIds(ids);
        }

    private void validateUserExists(List<Long> ids) {
        List<JkUserDO> list = jkUserMapper.selectByIds(ids);
        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
            throw exception(USER_NOT_EXISTS);
        }
    }

    private void validateUserExists(Long id) {
        if (jkUserMapper.selectById(id) == null) {
            throw exception(USER_NOT_EXISTS);
        }
    }

    @Override
    public JkUserDO getUser(Long id) {
        return jkUserMapper.selectById(id);
    }

    @Override
    public PageResult<JkUserDO> getUserPage(UserPageReqVO pageReqVO) {
        return jkUserMapper.selectPage(pageReqVO);
    }

    @Override
    public void sendSmsCodeRegister(AppAuthSmsSendReqVO reqVO) {
        // 校验账号是否存在
        List<JkUserDO> users = jkUserMapper.selectList(new LambdaQueryWrapperX<JkUserDO>()
                .eq(JkUserDO::getMobile, reqVO.getMobile()));

        //注册的时候，需要手机号不存在，存在代表该手机号已经注册过了
        if (!users.isEmpty()) {
            throw new ServiceException("该手机号已注册");
        }


        // 执行发送
//        SmsCodeSendReqDTO smsCodeSendReqDTO = new SmsCodeSendReqDTO()
//               .setMobile(reqVO.getMobile())
//               .setScene(SmsSceneEnum.JK_REGISTER.getScene())
//               .setCreateIp(getClientIP());
//        smsCodeApi.sendSmsCode(smsCodeSendReqDTO);
    }

    @Override
    public void sendSmsCodePasswordReset(AppAuthSmsSendReqVO reqVO) {
        // 校验账号是否存在
        // 校验账号是否存在
        List<JkUserDO> users = jkUserMapper.selectList(new LambdaQueryWrapperX<JkUserDO>()
                .eq(JkUserDO::getMobile, reqVO.getMobile()));

        //注册的时候，需要手机号不存在，存在代表该手机号已经注册过了
        if (!users.isEmpty()) {
            throw new ServiceException("该手机号已注册");
        }


        // 执行发送
//        SmsCodeSendReqDTO smsCodeSendReqDTO = new SmsCodeSendReqDTO()
//               .setMobile(reqVO.getMobile())
//               .setScene(SmsSceneEnum.JK_RESET_PASSWORD.getScene())
//               .setCreateIp(getClientIP());
//        smsCodeApi.sendSmsCode(smsCodeSendReqDTO);
    }

    @Override
    public void sendSmsCodeLogin(AppAuthSmsSendReqVO reqVO) {

        //校验验证码
        if(!appCaptchaService.validateCaptcha(reqVO.getCaptchaId(), reqVO.getCode())){
            throw exception(PIC_AUTH_CAPTCHA_CODE_ERROR);
        }

        // 校验账号是否存在
        List<JkUserDO> users = jkUserMapper.selectList(new LambdaQueryWrapperX<JkUserDO>()
                .eq(JkUserDO::getMobile, reqVO.getMobile()));

        //注册的时候，需要手机号不存在，存在代表该手机号已经注册过了
        if (users.isEmpty()) {
            throw new ServiceException("该手机号不存在");
        }


        // 执行发送
//        SmsCodeSendReqDTO smsCodeSendReqDTO = new SmsCodeSendReqDTO()
//               .setMobile(reqVO.getMobile())
//               .setScene(SmsSceneEnum.JK_LOGIN.getScene())
//               .setCreateIp(getClientIP());
//        smsCodeApi.sendSmsCode(smsCodeSendReqDTO);
    }

    @Override
    public AppAuthLoginRespVO resetPassword(AppResertPasswordReqVO reqVO) {
        // 校验账号是否存在
        List<JkUserDO> users = jkUserMapper.selectList(new LambdaQueryWrapperX<JkUserDO>()
                .eq(JkUserDO::getMobile, reqVO.getMobile()));

        //注册的时候，需要手机号不存在，存在代表该手机号已经注册过了
        if (users.isEmpty()) {
            throw new ServiceException("该手机号不存在");
        }
        JkUserDO user = users.get(0);

        // 校验验证码
        String userIp = getClientIP();
        SmsCodeUseReqDTO codeUseReqDTO = new SmsCodeUseReqDTO()
                .setCode(reqVO.getCode())
                .setScene(SmsSceneEnum.JK_RESET_PASSWORD.getScene())
                .setMobile(reqVO.getMobile())
                .setUsedIp(userIp);

        // 校验验证码
//        smsCodeApi.useSmsCode(codeUseReqDTO);

        user.setPassword(passwordEncoder.encode(reqVO.getNewPassword()));
        jkUserMapper.updateById(user);

        OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
                .setUserId(user.getId()).setUserType(getUserType().getValue())
                .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));

        return BeanUtils.toBean(accessTokenRespDTO, AppAuthLoginRespVO.class);

    }

    @Override
    @Transactional
    public AppAuthLoginRespVO smsLogin(AppAuthSmsLoginReqVO reqVO) {
        // 校验账号是否存在
        List<JkUserDO> users = jkUserMapper.selectList(new LambdaQueryWrapperX<JkUserDO>()
                .eq(JkUserDO::getMobile, reqVO.getMobile()));

        //注册的时候，需要手机号不存在，存在代表该手机号已经注册过了
        if (users.isEmpty()) {
            throw new ServiceException("该手机号不存在");
        }
        JkUserDO user = users.get(0);

        // 校验验证码
        String userIp = getClientIP();
        SmsCodeUseReqDTO codeUseReqDTO = new SmsCodeUseReqDTO()
                .setCode(reqVO.getCode())
                .setScene(SmsSceneEnum.JK_LOGIN.getScene())
                .setMobile(reqVO.getMobile())
                .setUsedIp(userIp);

        // 校验验证码
//        smsCodeApi.useSmsCode(codeUseReqDTO);


        // 创建 Token 令牌，记录登录日志
        return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_SMS);
    }

    @Override
    public AppAuthLoginRespVO login(AppAuthLoginReqVO reqVO) {

        //校验验证码
        if(!appCaptchaService.validateCaptcha(reqVO.getCaptchaId(), reqVO.getCode())){
            throw exception(PIC_AUTH_CAPTCHA_CODE_ERROR);
        }

        // 使用name + 密码，进行登录。
        JkUserDO user = login0(reqVO.getName(), reqVO.getPassword());

        // 创建 Token 令牌，记录登录日志
        return createTokenAfterLoginSuccess(user, reqVO.getName(), LoginLogTypeEnum.LOGIN_ERP_USERNAME);
    }


    private AppAuthLoginRespVO createTokenAfterLoginSuccess(JkUserDO user, String mobile,
                                                            LoginLogTypeEnum logType) {
        // 插入登陆日志
        createLoginLog(user.getId(), mobile, logType, LoginResultEnum.SUCCESS);
        // 创建 Token 令牌
        OAuth2AccessTokenRespDTO accessTokenRespDTO = oauth2TokenApi.createAccessToken(new OAuth2AccessTokenCreateReqDTO()
                .setUserId(user.getId()).setUserType(getUserType().getValue())
                .setClientId(OAuth2ClientConstants.CLIENT_ID_DEFAULT));

        return BeanUtils.toBean(accessTokenRespDTO, AppAuthLoginRespVO.class);
    }

    private JkUserDO login0(String name, String password) {
        final LoginLogTypeEnum logTypeEnum = LoginLogTypeEnum.LOGIN_MOBILE;
        // 校验账号是否存在
        JkUserDO user = jkUserMapper.selectOne(new LambdaQueryWrapperX<JkUserDO>()
                .eq(JkUserDO::getName, name));

        if (user == null) {
            createLoginLog(null, name, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
        }

        if (!passwordEncoder.matches(password, user.getPassword())) {
            createLoginLog(user.getId(), name, logTypeEnum, LoginResultEnum.BAD_CREDENTIALS);
            throw exception(AUTH_LOGIN_BAD_CREDENTIALS);
        }
        // 校验状态是否能登录
//        if (CommonStatusEnum.isDisable(user.getStatus())) {
//            createLoginLog(user.getId(), mobile, logTypeEnum, LoginResultEnum.USER_DISABLED);
//            throw exception(AUTH_LOGIN_USER_DISABLED);
//        }
        return user;
    }

    private void createLoginLog(Long userId, String mobile, LoginLogTypeEnum logType, LoginResultEnum loginResult) {
        // 插入登录日志
        LoginLogCreateReqDTO reqDTO = new LoginLogCreateReqDTO();
        reqDTO.setLogType(logType.getType());
        reqDTO.setTraceId(TracerUtils.getTraceId());
        reqDTO.setUserId(userId);
        reqDTO.setUserType(getUserType().getValue());
        reqDTO.setUsername(mobile);
        reqDTO.setUserAgent(ServletUtils.getUserAgent());
        reqDTO.setUserIp(getClientIP());
        reqDTO.setResult(loginResult.getResult());
        loginLogApi.createLoginLog(reqDTO);
        // 更新最后登录时间
//        if (userId != null && Objects.equals(LoginResultEnum.SUCCESS.getResult(), loginResult.getResult())) {
//            erpSupplierService.updateUserLogin(userId, getClientIP());
//        }
    }


    private UserTypeEnum getUserType() {
        return UserTypeEnum.ERP_USER;
    }







}
